﻿using System;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

namespace ZealandIT.MsBuildTasks.Svn
{
    /// <summary>
    /// Retrieves the latest changed revision for a local working copy.
    /// Required because SvnVersion (svnversion.exe) returns the latest Revision which
    /// applies to the whole repository, and which therefore is incorrect to use 
    /// when you have multiple different projects in a single repository, with each
    /// specific project needing its own revision-associated version number.
    /// </summary>
    public class SvnLastChangedRev : ToolTask
    {
        private static readonly Regex _numberRegex = new Regex(@"Last Changed Rev: (?<rev>\d+)", RegexOptions.Compiled);

        private string _localPath;
        private int _revision=0;
        private StringBuilder _outputBuffer;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SvnLastChangedRev()
        {
            _outputBuffer = new StringBuilder();        
        }

        /// <summary>Path to local working copy.</summary>
        [Required]
        public string LocalPath
        {
            get { return _localPath; }
            set { _localPath = value; }
        }

        /// <summary>Last changed Revision number of the local working folder.</summary>
        [Output]
        public int Revision
        {
            get { return _revision; }
            set { _revision = value; }
        }

        #region Task Overrides
        /// <summary>
        /// Returns the fully qualified path to the executable file.
        /// </summary>
        /// <returns>
        /// The fully qualified path to the executable file.
        /// </returns>
        protected override string GenerateFullPathToTool()
        {            
            return Path.Combine(ToolPath, ToolName);
        }

        /// <summary>
        /// Logs the starting point of the run to all registered loggers.
        /// </summary>
        /// <param name="message">A descriptive message to provide loggers, usually the command line and switches.</param>
        protected override void LogToolCommand(string message)
        {
            Log.LogCommandLine(MessageImportance.Low, message);
        }

        /// <summary>
        /// Gets the <see cref="T:Microsoft.Build.Framework.MessageImportance"></see> with which to log errors.
        /// </summary>
        /// <value></value>
        /// <returns>The <see cref="T:Microsoft.Build.Framework.MessageImportance"></see> with which to log errors.</returns>
        protected override MessageImportance StandardOutputLoggingImportance
        {
            get { return MessageImportance.Normal; }
        }

        /// <summary>
        /// Gets the name of the executable file to run.
        /// </summary>
        /// <value></value>
        /// <returns>The name of the executable file to run.</returns>
        protected override string ToolName
        {
            get { return "svn.exe"; }
        }

        /// <summary>
        /// Returns a string value containing the command line arguments to pass directly to the executable file.
        /// </summary>
        /// <returns>
        /// A string value containing the command line arguments to pass directly to the executable file.
        /// </returns>
        protected override string GenerateCommandLineCommands()
        {
            DirectoryInfo localPath = new DirectoryInfo(_localPath);
            return string.Format("info \"{0}\"", localPath.FullName.Replace('\\', '/'));
        }

        /// <summary>
        /// Runs the exectuable file with the specified task parameters.
        /// </summary>
        /// <returns>
        /// true if the task runs successfully; otherwise, false.
        /// </returns>
        public override bool Execute()
        {
            bool result = base.Execute();
            if (result)
            {
                ParseOutput();
            }
            return result;
        }

        /// <summary>
        /// Logs the events from text output.
        /// </summary>
        /// <param name="singleLine">The single line.</param>
        /// <param name="messageImportance">The message importance.</param>
        protected override void LogEventsFromTextOutput(string singleLine, Microsoft.Build.Framework.MessageImportance messageImportance)
        {
            base.LogEventsFromTextOutput(singleLine, messageImportance);
            _outputBuffer.Append(singleLine);
        }

        #endregion Task Overrides

        #region Private Methods
        private void ParseOutput()
        {
            string buffer = _outputBuffer.ToString();
            Match match = _numberRegex.Match(buffer);
            if (match.Success)
            {
                _revision = Convert.ToInt32(match.Groups["rev"].Value);
            }
        }

        #endregion Private Methods

    }
}